//+------------------------------------------------------------------+
//|                                                      Scrolls.mqh |
//|                             Copyright 2000-2025, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#include "WndContainer.h"                          // 容器窗口基类（提供控件组合能力）
#include "Panel.h"                                 // 面板类（用于滚动条背景）
#include "BmpButton.h"                             // 位图按钮类（用于滚动按钮和滑块）

//+------------------------------------------------------------------+
//| 资源定义：滚动条所需的位图资源                                    |
//+------------------------------------------------------------------+
#resource "res\\Up.bmp"          // 垂直滚动条“向上”按钮图片
#resource "res\\ThumbVert.bmp"   // 垂直滚动条滑块图片
#resource "res\\Down.bmp"        // 垂直滚动条“向下”按钮图片
#resource "res\\Left.bmp"        // 水平滚动条“向左”按钮图片
#resource "res\\ThumbHor.bmp"    // 水平滚动条滑块图片
#resource "res\\Right.bmp"       // 水平滚动条“向右”按钮图片

//+------------------------------------------------------------------+
//| CScroll 类：滚动条基类                                            |
//| 核心能力：封装滚动条通用逻辑（背景、按钮、滑块、位置控制），        |
//|           为垂直/水平滚动条提供统一接口，支持位置范围设置与事件通知  |
//| 适用场景：作为垂直/水平滚动条子类的父类，不直接实例化              |
//+------------------------------------------------------------------+
class CScroll : public CWndContainer
  {
protected:
   // 子控件（保护，子类可访问）
   CPanel            m_back;                // 滚动条背景面板（装饰与区域界定）
   CBmpButton        m_inc;                 // 增量按钮（垂直=向下，水平=向右，用于增加滚动位置）
   CBmpButton        m_dec;                 // 减量按钮（垂直=向上，水平=向左，用于减少滚动位置）
   CBmpButton        m_thumb;               // 滑块（滚动条核心交互元素，可拖拽调整位置）

   // 滚动位置参数（保护，子类可修改）
   int               m_min_pos;             // 最小滚动位置（默认 0）
   int               m_max_pos;             // 最大滚动位置（默认 0，需根据内容长度设置）
   int               m_curr_pos;            // 当前滚动位置（初始 0，范围：m_min_pos ~ m_max_pos）

public:
   //----------------------------------------------------------------
   // 构造与析构函数
   //----------------------------------------------------------------
   /**
    * @brief 构造函数：初始化滚动条默认状态
    * @details 初始化滚动位置参数（当前/最小/最大位置均为 0），子控件待 Create 时创建
    */
                     CScroll(void);

   /**
    * @brief 析构函数：清理滚动条资源
    * @details 依赖父类 CWndContainer 的析构逻辑，自动释放子控件（背景、按钮、滑块）
    */
                    ~CScroll(void);

   //----------------------------------------------------------------
   // 控件创建：初始化滚动条基础结构
   //----------------------------------------------------------------
   /**
    * @brief 创建滚动条基础控件（背景、按钮、滑块）
    * @param chart [in] 目标图表ID（0 表示当前活跃图表）
    * @param name [in] 控件唯一标识名（图表内不可重复）
    * @param subwin [in] 绑定的子窗口编号（0 = 主窗口，≥1 = 指标子窗口）
    * @param x1 [in] 左上角X坐标（像素，相对于图表窗口）
    * @param y1 [in] 左上角Y坐标（像素）
    * @param x2 [in] 右下角X坐标（像素）
    * @param y2 [in] 右下角Y坐标（像素）
    * @return bool - 创建结果：true=成功（父类初始化+子控件创建完成），false=失败
    * @note 子类需重写 CreateInc/CreateDec/CreateThumb 实现具体按钮/滑块的布局
    */
   virtual bool      Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2);

   //----------------------------------------------------------------
   // 事件处理：响应滚动条相关事件
   //----------------------------------------------------------------
   /**
    * @brief 处理滚动条事件（按钮点击、滑块拖拽等）
    * @param id [in] 事件ID（如 ON_CLICK、ON_DRAG 等）
    * @param lparam [in] 长整数参数（事件相关数据）
    * @param dparam [in] 双精度参数（事件相关数据）
    * @param sparam [in] 字符串参数（通常为控件名称，用于识别事件来源）
    * @return bool - 处理结果：true=事件已处理，false=未处理（交由父类处理）
    */
   virtual bool      OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam);

   //----------------------------------------------------------------
   // 滚动范围配置：设置/获取最小/最大滚动位置
   //----------------------------------------------------------------
   /**
    * @brief 获取最小滚动位置
    * @return int - 最小滚动位置（默认 0）
    */
   int               MinPos(void)           const;

   /**
    * @brief 设置最小滚动位置
    * @param value [in] 目标最小位置（≤ m_max_pos）
    * @note 设置后会自动调整当前位置（若 m_curr_pos < value，强制设为 value）
    */
   void              MinPos(const int value);

   /**
    * @brief 获取最大滚动位置
    * @return int - 最大滚动位置（默认 0）
    */
   int               MaxPos(void)           const;

   /**
    * @brief 设置最大滚动位置
    * @param value [in] 目标最大位置（≥ m_min_pos）
    * @note 设置后会自动调整当前位置（若 m_curr_pos > value，强制设为 value）
    */
   void              MaxPos(const int value);

   //----------------------------------------------------------------
   // 滚动位置控制：设置/获取当前滚动位置
   //----------------------------------------------------------------
   /**
    * @brief 获取当前滚动位置
    * @return int - 当前滚动位置（范围：m_min_pos ~ m_max_pos）
    */
   int               CurrPos(void)          const;

   /**
    * @brief 设置当前滚动位置
    * @param value [in] 目标位置（自动被限制在 m_min_pos ~ m_max_pos 范围内）
    * @return bool - 设置结果：true=位置发生变化，false=位置未变化
    * @note 位置变化时会调用 OnChangePos() 更新滑块显示，并触发相关事件
    */
   bool              CurrPos(int value);

protected:
   //----------------------------------------------------------------
   // 子控件创建：子类需重写以实现具体布局（保护，仅子类可重写）
   //----------------------------------------------------------------
   /**
    * @brief 创建滚动条背景面板
    * @return bool - 创建结果：true=成功（背景样式配置完成），false=失败
    */
   virtual bool      CreateBack(void);

   /**
    * @brief 创建增量按钮（垂直=向下，水平=向右）
    * @return bool - 创建结果：true=成功，false=失败（子类需重写实现）
    */
   virtual bool      CreateInc(void);

   /**
    * @brief 创建减量按钮（垂直=向上，水平=向左）
    * @return bool - 创建结果：true=成功，false=失败（子类需重写实现）
    */
   virtual bool      CreateDec(void);

   /**
    * @brief 创建滑块（滚动条核心交互元素）
    * @return bool - 创建结果：true=成功，false=失败（子类需重写实现）
    */
   virtual bool      CreateThumb(void);

   //----------------------------------------------------------------
   // 按钮事件回调：处理增量/减量按钮点击（保护，仅子类可重写）
   //----------------------------------------------------------------
   /**
    * @brief 增量按钮点击事件回调（点击后增加当前位置）
    * @return bool - 处理结果：true=成功（位置更新+事件通知），false=失败
    */
   virtual bool      OnClickInc(void);

   /**
    * @brief 减量按钮点击事件回调（点击后减少当前位置）
    * @return bool - 处理结果：true=成功（位置更新+事件通知），false=失败
    */
   virtual bool      OnClickDec(void);

   //----------------------------------------------------------------
   // 生命周期事件回调：处理显示/隐藏（保护，仅子类可重写）
   //----------------------------------------------------------------
   /**
    * @brief 滚动条显示事件回调
    * @return bool - 处理结果：true=成功（发送 ON_SHOW 事件通知），false=失败
    */
   virtual bool      OnShow(void);

   /**
    * @brief 滚动条隐藏事件回调
    * @return bool - 处理结果：true=成功（发送 ON_HIDE 事件通知），false=失败
    */
   virtual bool      OnHide(void);

   //----------------------------------------------------------------
   // 位置更新回调：滚动位置变化时触发（保护，仅子类可重写）
   //----------------------------------------------------------------
   /**
    * @brief 滚动位置变化时的回调（用于更新滑块位置）
    * @return bool - 处理结果：true=成功（滑块位置更新），false=失败（子类需重写实现）
    */
   virtual bool      OnChangePos(void);

   //----------------------------------------------------------------
   // 滑块拖拽回调：处理滑块拖拽逻辑（保护，仅子类可重写）
   //----------------------------------------------------------------
   /**
    * @brief 滑块拖拽开始事件回调
    * @return bool - 处理结果：true=成功（初始化拖拽参数），false=失败（子类需重写实现）
    */
   virtual bool      OnThumbDragStart(void);

   /**
    * @brief 滑块拖拽过程事件回调
    * @return bool - 处理结果：true=成功（根据拖拽位置更新滚动位置），false=失败（子类需重写实现）
    */
   virtual bool      OnThumbDragProcess(void);

   /**
    * @brief 滑块拖拽结束事件回调
    * @return bool - 处理结果：true=成功（清理拖拽资源），false=失败（子类需重写实现）
    */
   virtual bool      OnThumbDragEnd(void);

   //----------------------------------------------------------------
   // 辅助方法：根据坐标计算滚动位置（保护，仅子类可重写）
   //----------------------------------------------------------------
   /**
    * @brief 根据滑块坐标计算对应的滚动位置
    * @param coord [in] 滑块坐标（垂直=Y轴，水平=X轴）
    * @return int - 计算出的滚动位置（子类需重写实现）
    */
   virtual int       CalcPos(const int coord);
  };

//+------------------------------------------------------------------+
//| CScroll 事件映射：关联子控件事件到处理函数（用于IDE智能提示）        |
//+------------------------------------------------------------------+
// EVENT_MAP_BEGIN(CScroll)
//    ON_EVENT(ON_CLICK, m_inc, OnClickInc)                // 增量按钮点击 → 调用 OnClickInc
//    ON_EVENT(ON_CLICK, m_dec, OnClickDec)                // 减量按钮点击 → 调用 OnClickDec
//    ON_EVENT(ON_DRAG_START, m_thumb, OnThumbDragStart)   // 滑块拖拽开始 → 调用 OnThumbDragStart
//    ON_EVENT_PTR(ON_DRAG_PROCESS, m_drag_object, OnThumbDragProcess)  // 滑块拖拽过程 → 调用 OnThumbDragProcess
//    ON_EVENT_PTR(ON_DRAG_END, m_drag_object, OnThumbDragEnd)          // 滑块拖拽结束 → 调用 OnThumbDragEnd
// EVENT_MAP_END(CWndContainer)

//+------------------------------------------------------------------+
//| CScrollV 类：垂直滚动条                                           |
//| 核心能力：继承 CScroll，实现垂直方向滚动逻辑，支持上下按钮控制、    |
//|           滑块拖拽，适配垂直方向的内容滚动（如列表、文本框等）       |
//| 适用场景：需要垂直滚动的容器（如 ListView、长文本面板等）           |
//+------------------------------------------------------------------+
class CScrollV : public CScroll
  {
public:
   //----------------------------------------------------------------
   // 构造与析构函数
   //----------------------------------------------------------------
   /**
    * @brief 构造函数：初始化垂直滚动条默认状态
    * @details 依赖父类 CScroll 构造逻辑，无额外初始化
    */
                     CScrollV(void);

   /**
    * @brief 析构函数：清理垂直滚动条资源
    * @details 依赖父类 CScroll 析构逻辑，自动释放子控件
    */
                    ~CScrollV(void);

protected:
   //----------------------------------------------------------------
   // 子控件创建：重写父类方法，实现垂直滚动条布局（保护，仅内部调用）
   //----------------------------------------------------------------
   /**
    * @brief 创建垂直滚动条的增量按钮（向下按钮，位于滚动条底部）
    * @return bool - 创建结果：true=成功（按钮位置、图片配置完成），false=失败
    */
   virtual bool      CreateInc(void);

   /**
    * @brief 创建垂直滚动条的减量按钮（向上按钮，位于滚动条顶部）
    * @return bool - 创建结果：true=成功（按钮位置、图片配置完成），false=失败
    */
   virtual bool      CreateDec(void);

   /**
    * @brief 创建垂直滚动条的滑块（垂直方向可拖拽）
    * @return bool - 创建结果：true=成功（滑块位置、图片、拖拽属性配置完成），false=失败
    */
   virtual bool      CreateThumb(void);

   //----------------------------------------------------------------
   // 生命周期事件回调：重写父类方法（保护，仅子类可重写）
   //----------------------------------------------------------------
   /**
    * @brief 垂直滚动条尺寸变化事件回调
    * @return bool - 处理结果：true=成功（固定宽度+调整按钮/滑块位置），false=失败
    */
   virtual bool      OnResize(void);

   /**
    * @brief 垂直滚动条位置变化事件回调（更新滑块Y坐标）
    * @return bool - 处理结果：true=成功（根据滚动位置计算并移动滑块），false=失败
    */
   virtual bool      OnChangePos(void);

   //----------------------------------------------------------------
   // 滑块拖拽回调：重写父类方法（保护，仅子类可重写）
   //----------------------------------------------------------------
   /**
    * @brief 垂直滑块拖拽开始事件回调（初始化拖拽范围为垂直方向）
    * @return bool - 处理结果：true=成功（创建拖拽辅助对象+设置Y轴限制），false=失败
    */
   virtual bool      OnThumbDragStart(void);

   /**
    * @brief 垂直滑块拖拽过程事件回调（根据Y坐标更新滚动位置）
    * @return bool - 处理结果：true=成功（计算新位置+发送滚动事件），false=失败
    */
   virtual bool      OnThumbDragProcess(void);

   /**
    * @brief 垂直滑块拖拽结束事件回调（清理拖拽资源）
    * @return bool - 处理结果：true=成功（销毁拖拽对象+重置滑块状态），false=失败
    */
   virtual bool      OnThumbDragEnd(void);

   //----------------------------------------------------------------
   // 辅助方法：重写父类方法（保护，仅内部调用）
   //----------------------------------------------------------------
   /**
    * @brief 根据滑块Y坐标计算垂直滚动位置
    * @param coord [in] 滑块Y轴坐标（像素）
    * @return int - 对应的滚动位置（范围：m_min_pos ~ m_max_pos）
    */
   virtual int       CalcPos(const int coord);
  };

//+------------------------------------------------------------------+
//| CScrollH 类：水平滚动条                                           |
//| 核心能力：继承 CScroll，实现水平方向滚动逻辑，支持左右按钮控制、    |
//|           滑块拖拽，适配水平方向的内容滚动（如长文本、表格等）       |
//| 适用场景：需要水平滚动的容器（如长标题栏、宽表格、横向列表等）       |
//+------------------------------------------------------------------+
class CScrollH : public CScroll
  {
public:
   //----------------------------------------------------------------
   // 构造与析构函数
   //----------------------------------------------------------------
   /**
    * @brief 构造函数：初始化水平滚动条默认状态
    * @details 依赖父类 CScroll 构造逻辑，无额外初始化
    */
                     CScrollH(void);

   /**
    * @brief 析构函数：清理水平滚动条资源
    * @details 依赖父类 CScroll 析构逻辑，自动释放子控件
    */
                    ~CScrollH(void);

protected:
   //----------------------------------------------------------------
   // 子控件创建：重写父类方法，实现水平滚动条布局（保护，仅内部调用）
   //----------------------------------------------------------------
   /**
    * @brief 创建水平滚动条的增量按钮（向右按钮，位于滚动条右侧）
    * @return bool - 创建结果：true=成功（按钮位置、图片配置完成），false=失败
    */
   virtual bool      CreateInc(void);

   /**
    * @brief 创建水平滚动条的减量按钮（向左按钮，位于滚动条左侧）
    * @return bool - 创建结果：true=成功（按钮位置、图片配置完成），false=失败
    */
   virtual bool      CreateDec(void);

   /**
    * @brief 创建水平滚动条的滑块（水平方向可拖拽）
    * @return bool - 创建结果：true=成功（滑块位置、图片、拖拽属性配置完成），false=失败
    */
   virtual bool      CreateThumb(void);

   //----------------------------------------------------------------
   // 生命周期事件回调：重写父类方法（保护，仅子类可重写）
   //----------------------------------------------------------------
   /**
    * @brief 水平滚动条尺寸变化事件回调
    * @return bool - 处理结果：true=成功（固定高度+调整按钮/滑块位置），false=失败
    */
   virtual bool      OnResize(void);

   /**
    * @brief 水平滚动条位置变化事件回调（更新滑块X坐标）
    * @return bool - 处理结果：true=成功（根据滚动位置计算并移动滑块），false=失败
    */
   virtual bool      OnChangePos(void);

   //----------------------------------------------------------------
   // 滑块拖拽回调：重写父类方法（保护，仅子类可重写）
   //----------------------------------------------------------------
   /**
    * @brief 水平滑块拖拽开始事件回调（初始化拖拽范围为水平方向）
    * @return bool - 处理结果：true=成功（创建拖拽辅助对象+设置X轴限制），false=失败
    */
   virtual bool      OnThumbDragStart(void);

   /**
    * @brief 水平滑块拖拽过程事件回调（根据X坐标更新滚动位置）
    * @return bool - 处理结果：true=成功（计算新位置+发送滚动事件），false=失败
    */
   virtual bool      OnThumbDragProcess(void);

   /**
    * @brief 水平滑块拖拽结束事件回调（清理拖拽资源）
    * @return bool - 处理结果：true=成功（销毁拖拽对象+重置滑块状态），false=失败
    */
   virtual bool      OnThumbDragEnd(void);

   //----------------------------------------------------------------
   // 辅助方法：重写父类方法（保护，仅内部调用）
   //----------------------------------------------------------------
   /**
    * @brief 根据滑块X坐标计算水平滚动位置
    * @param coord [in] 滑块X轴坐标（像素）
    * @return int - 对应的滚动位置（范围：m_min_pos ~ m_max_pos）
    */
   virtual int       CalcPos(const int coord);
  };
//+------------------------------------------------------------------+